#ifndef POPUP_ABSTRACT_MESSAGE_H
#define POPUP_ABSTRACT_MESSAGE_H

#include <string>
#include <vector>
#include <set>
#include <map>
#include <PopupOSAL.hpp>
#include "PopupMessage.hpp"
#include <PopupLoggerUI.hpp>
#include "PopupSSL.hpp"

namespace Popup
{
  struct AbstractMessage
  {
  public:

    virtual ~AbstractMessage();

    //! Checks for message coherence
    inline bool isValid() const { return valid; }

  protected:

    AbstractMessage(MsgType p_id = POPUP_MSG_TYPE_UNK,
                         MsgEncryption p_encryption = POPUP_ENCRYPTION_NONE);

    //! Sets up message from the given message
    bool deserialize(const Message *p_message);

    //! Sets up message to be ready for sending over the network
    virtual bool onSend() { return true; }

    //! Notifies user that a message has been received
    virtual bool onReceive() { return true; }

    bool payloadAddData(unsigned short fieldId,
                        const void *p_data = 0,
                        size_t p_size = 0,
                        unsigned short p_type = POPUP_FIELD_DATA_TYPE_UNK);

    bool payloadAddOpaqueData(unsigned short fieldId,
                              size_t p_size, void **p_payloadBuffer);

    bool payloadAddFileContent(unsigned short fieldId,
                               const std::string & p_path);

    bool payloadAddString(unsigned short fieldId,
                          const std::string & p_value);

    bool payloadAddString(unsigned short fieldId,
                          const std::vector<std::string> & p_values);

    bool payloadAddBoolean(unsigned short fieldId, bool p_value);

    bool payloadAddShort(unsigned short p_fieldId, unsigned short p_value);

    bool payloadAddShort(unsigned short p_fieldId,
                        const std::vector<unsigned short> & p_values);

    bool payloadAddLong(unsigned short p_fieldId, unsigned int  p_value);

    bool payloadAddLong(unsigned short p_fieldId,
                        const std::set<unsigned int > & p_values);

    bool payloadAddLongLong(unsigned short p_fieldId, unsigned long long p_value);

    bool payloadAddLongLong(unsigned short p_fieldId,
                            const std::set<unsigned long long> & p_values);

    const MessageField *payloadGetField(unsigned short fieldId) const;

    bool payloadGetString(unsigned short p_fieldId,
                          std::string & p_value) const;

    bool payloadGetString(unsigned short p_fieldId,
                          std::vector<std::string> & p_values) const;

    bool payloadGetBoolean(unsigned short p_fieldId,
                           bool & p_value) const;

    bool payloadGetShort(unsigned short p_fieldId,
                         unsigned short & p_value) const;

    bool payloadGetShort(unsigned short p_fieldId,
                        std::vector<unsigned short> & p_values) const;

    bool payloadGetLong(unsigned short p_fieldId,
                        unsigned int  & p_value) const;

    bool payloadGetLong(unsigned short p_fieldId,
                        std::set<unsigned int > & p_values) const;

    bool payloadGetLongLong(unsigned short p_fieldId,
                            unsigned long long & p_value) const;

    bool payloadGetLongLong(unsigned short p_fieldId,
                            std::set<unsigned long long> & p_values) const;

    bool payloadDumpFieldToFile(unsigned short p_fieldId,
                                const std::string & p_filepath) const;

    bool payloadDumpFieldToFile(unsigned short p_fieldId,
                                PopupUtils::FileStream *p_file) const;

    bool payloadAddFromFile(unsigned short p_fieldId,
                            PopupUtils::FileStream *p_file,
                            unsigned int  p_size);

    //========================================================
    // Private methods which will be used by the friend class
    // PopupNetworkMessage
    //========================================================

  private:

    friend class MessageNetworker;

    //! Sets up raw message to be ready for sending
    bool prepareSend();

    //! Returns util message size (ie. protocol header excluded)
    size_t getUtilMessageSize() const;

    //! Returns the total message, protocol header included
    size_t getTotalMessageSize() const;

    //========================================================
    // Class members
    //========================================================

  protected:
    FieldsMap fields;

  private:
    bool allocate(size_t p_datasize);

    unsigned short type;
    MsgEncryption encryption;
    size_t payloadSize;
    size_t freePayloadSize;

    //! Util message
    Message *message;
    //! Full message
    RawMessage *fullMessage;

    //! Validity of the message
    bool valid;
    bool prepareDone;
  };
}

#endif
